<template>
  <div class="dpro-dropdown">
    <div
      ref="dropdownTrigger"
      :class="['dpro-dropdown-trigger', { 'disabled': disabled }, { 'open': _placementVisible }]"
      @mouseenter="mouseenterHandler"
      @mouseleave="mouseleaveHandler"
      @click="clickTrigger"
    >
      <slot></slot>
    </div>
    <div>
      <div
        ref="placementWrapper"
        :class="['dpro-dropdown-placement', overlayClassName ? overlayClassName : '']"
        :style="{ 'top': `${top}px`, 'left': `${left}px` }"
        v-show="_placementVisible"
        @mouseenter="placementMouseenterHandler"
        @mouseleave="placementMouseleaveHandler"
      >
        <slot name="overlay"></slot>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: 'DproDropdown',
  props: {
    /**
     * 菜单是否显示
     */
    value: {
      type: [Boolean, undefined],
      default: undefined
    },
    /**
     * 触发下拉的行为
     * < click | hover | contextmenu >
     */
    trigger: {
      type: Array,
      default: () => ['hover']
    },
    /**
     * 菜单弹出位置：bottomLeft bottomCenter bottomRight topLeft topCenter topRight
     */
    placement: {
      type: String,
      default: 'bottomLeft'
    },
    /**
     * 下拉根元素的类名称
     */
    overlayClassName: {
      type: String
    },
    /**
     * 菜单是否禁用
     */
    disabled: {
      type: Boolean,
      default: false
    },
    /**
     * 菜单渲染父节点。默认渲染到 body 上，如果你遇到菜单滚动定位问题，试试修改为滚动的区域，并相对其定位。
     */
    getPopupContainer: {
      type: Function,
      default: () => document.body
    }
  },
  data() {
    return {
      popEl: '',
      placementVisible: false,
      top: 0,
      left: 0,
      placementHover: false,
      triggerhover: false
    }
  },
  computed: {
    _placementVisible() {
      return this.$props.value !== undefined ? this.$props.value : this.placementVisible;
    }
  },
  watch: {
    // 父组件控制隐藏时移除点击事件监听
    _placementVisible(val) {
      val ? this.bindBodyClickEvent() : this.removeBodyClickEvent();
    }
  },
  mounted() {
    this.$nextTick(() => {
      this.setPopupContainer();
    })
    window.addEventListener('resize', this.resizeHandler, true);
  },
  beforeDestroy() {
    window.removeEventListener('resize', this.resizeHandler, true);
    this.removeBodyClickEvent();
    this.removeNode();
  },
  methods: {
    setPopupContainer() {
      let popParentEl = this.getPopupContainer(),
        popEl = this.$refs.placementWrapper,
        triggerEl = this.$refs.dropdownTrigger,
        offsetTop = triggerEl.offsetTop,
        offsetLeft = triggerEl.offsetLeft,
        // clientWidth = triggerEl.clientWidth,
        clientHeight = triggerEl.clientHeight,
        // offsetWidth = triggerEl.offsetWidth,
        // offsetHeight = triggerEl.offsetHeight,
        // popClientWidth = popEl.clientWidth,
        // popClientHeight = popEl.clientHeight,
        top = offsetTop + clientHeight,
        left = offsetLeft;
        // diffWidth = clientWidth - popClientWidth,
        // diffHeight = clientHeight - popClientHeight;
      console.log(`
        offsetTop:${offsetTop};
        offsetLeft:${offsetLeft};
        clientHeight:${clientHeight};
      `);
        // clientWidth:${clientWidth};
        // offsetWidth:${offsetWidth};
        // offsetHeight:${offsetHeight};
        // popClientWidth:${popClientWidth};
        // popClientHeight:${popClientHeight}
      // console.log(`diffWidth:${diffWidth};diffHeight:${diffHeight}`)
      // switch(this.placement) {
      //   case 'bottomLeft':
      //     top = offsetTop + clientHeight;
      //     left = offsetLeft;
      //     break;
      //   case 'bottomCenter': 
      //     top = offsetTop + clientHeight;
      //     left = offsetLeft + (diffWidth / 2) > 0 ? offsetLeft + (diffWidth / 2) : 0;
      //     break;
      //   case 'bottomRight': 
      //     top = offsetTop + clientHeight;
      //     left = offsetLeft + diffWidth > 0 ? offsetLeft + diffWidth : 0;
      //     break;
      //   case 'topLeft': 
      //     top = offsetTop - popClientHeight > 0 ? offsetTop - popClientHeight : 0;
      //     left = offsetLeft;
      //     break;
      //   case 'topCenter': 
      //     top = offsetTop - popClientHeight > 0 ? offsetTop - popClientHeight : 0;
      //     left = offsetLeft + diffWidth / 2 > 0 ? offsetLeft + diffWidth / 2 : 0;
      //     break;
      //   case 'topRight': 
      //     top = offsetTop - popClientHeight > 0 ? offsetTop - popClientHeight : 0;
      //     left = offsetLeft + diffWidth > 0 ? offsetLeft + diffWidth : 0;
      //     break;
      // }
      this.top = top;
      this.left = left;
      this.popEl = popEl.parentNode.removeChild(popEl);
      popParentEl.appendChild(popEl);
    },
    // 更新top和left值
    updatePosition() {
      let triggerEl = this.$refs.dropdownTrigger;
      if(!triggerEl) return;
      this.top = triggerEl.offsetTop + triggerEl.clientHeight;
      this.left = triggerEl.offsetLeft;
    },
    removeNode() {
      // console.log('removeNode', this.popEl);
      this.getPopupContainer().removeChild(this.popEl);
    },
    async clickTrigger() {
      // console.log('clickTrigger', this._placementVisible);
      if(this.disabled || !this.trigger.includes('click')) return;
      this.setVisible(!this._placementVisible);
    },
    bindBodyClickEvent() {
      document.body.addEventListener('click', this.clickBodyHandler, false);
    },
    removeBodyClickEvent() {
      document.body.removeEventListener('click', this.clickBodyHandler, false);
    },
    clickBodyHandler(e) {
      if(!this._placementVisible) return;
      let composedPath = e.composedPath();
      if(composedPath.includes(this.$refs.placementWrapper) || composedPath.includes(this.$refs.dropdownTrigger)) {
        console.log('no hide');
        return;
      }
      this.hidePlacement(17);

      // // console.log('body-click', e);
      // if(e.path?.includes(this.$refs.placementWrapper) && this.$props.value !== undefined) {
      //   // 点击overlay下的元素时不触发隐藏
      //   // console.log('11111');
      //   return;
      // }
      // this.hidePlacement(17);
      // this.removeBodyClickEvent();
    },
    mouseenterHandler() {
      if(this.disabled || !this.trigger.includes('hover')) return;
      // console.log('mouseenterHandler');
      // this.$emit('input', true);
      this.setVisible(true);
      this.triggerhover = true;
    },
    mouseleaveHandler() {
      if(this.disabled || !this.trigger.includes('hover')) return;
      // console.log('mouseleaveHandler');
      this.triggerhover = false;
      this.hidePlacement();
    },
    placementMouseenterHandler() {
      if(this.disabled || !this.trigger.includes('hover')) return;
      this.placementHover = true;
    },
    placementMouseleaveHandler() {
      if(this.disabled || !this.trigger.includes('hover')) return;
      this.placementHover = false;
      this.hidePlacement();
    },
    hidePlacement(delay = 500) {
      setTimeout(() => {
        if(this.placementHover || this.triggerhover) return;
        this.setVisible(false);
      }, delay);
    },
    setVisible(visible) {
      let visibleOld = this._placementVisible;
      // 每次显示时获取最新位置
      visible && this.updatePosition();

      if(this.$props.value === undefined) {
        this.placementVisible = visible;
      } else {
        this.$emit('input', visible);
      }
      visibleOld !== this._placementVisible && this.$emit('visibleChange', this._placementVisible);
    },
    // 页面resize时更新定位
    resizeHandler() {
      this._placementVisible && this.updatePosition();
    }
  }
}
</script>

<style lang="less" scoped>
.dpro-dropdown {
  font-size: 14px;
}
.icon {
  width: 1rem;
  height: 1rem;
  vertical-align: -0.15rem;
  fill: currentColor;
  overflow: hidden;
}
.dpro-dropdown-trigger {
  display: inline-block;
  cursor: pointer;
  &.disabled {
    cursor: not-allowed;
    opacity: 0.8;
  }
}
</style>
<style lang="less">
.dpro-dropdown-placement {
  box-sizing: border-box;
  position: absolute;
  display: block;
  margin: 0;
  padding: 0;
  font-size: 14px;
  list-style: none;
  z-index: 1050;
}
</style>